﻿using System;
using System.Collections.Generic;
using AutoClub.Controllers;
using AutoClub.Core.Domain;
using AutoClub.Core.Domain.Dao;
using AutoClub.Helper.Tests;
using AutoClub.Models;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace AutoClub.Tests
{
    /// <summary>
    /// Test Suite for the race controller
    /// </summary>
    [TestClass]
    public class RaceControllerTests
    {
        private ViewModelHelper vmHelper;
        private ModelHelper modelHelper;
        private MockRepository mockRepository;
        private IModelMapper modelMapperMock;
        private ICarCategoriesRepo carCategoriesRepoMock;
        private IRaceRepo raceRepoMock;
        private RaceController controller;
        private IUnitOfWork uow;

        [TestInitialize()]
        public void MyTestInitialize()
        {
            this.mockRepository = new MockRepository();
            this.modelMapperMock = this.mockRepository.StrictMock<IModelMapper>();
            this.carCategoriesRepoMock = this.mockRepository.StrictMock<ICarCategoriesRepo>();
            this.raceRepoMock = this.mockRepository.StrictMock<IRaceRepo>();
            this.uow = this.mockRepository.StrictMock<IUnitOfWork>();
            this.vmHelper = new ViewModelHelper();
            this.modelHelper = new ModelHelper();
            this.controller = new RaceController(this.uow, this.carCategoriesRepoMock, this.raceRepoMock, this.modelMapperMock);
        }

        [TestCleanup()]
        public void MyTestCleanup()
        {
            this.mockRepository = null;
            this.modelMapperMock = null;
            this.carCategoriesRepoMock = null;
            this.raceRepoMock = null;
        }

        [TestMethod]
        public void AddNewRaceFromUI()
        {
            // Setup
            AddRaceModel model = this.vmHelper.CreateAddRaceModel(DateTime.Today.AddDays(-7), DateTime.Today.AddDays(7), 8, (int)CarCategoryEnum.Category2);
            Race expectedRace = this.modelHelper.CreateRace(model.StartDate.Value, model.EndDate.Value, model.MechanicsMaxAmount, CarCategoryEnum.Category2, RaceStateEnum.Opened);
            IList<CarCategory> categories = this.modelHelper.CreateAllCarCategories();
            IList<RaceState> raceStates = this.modelHelper.CreateAllRaceStates();

            Expect.Call(this.modelMapperMock.Map<AddRaceModel, Race>(model))
                .Repeat.Once()
                .Return(expectedRace);

            Expect.Call(this.carCategoriesRepoMock.GetAll())
                .Repeat.Once()
                .Return(categories);

            Expect.Call(this.raceRepoMock.GetAllRaceStates())
                .Repeat.Once()
                .Return(raceStates);

            Expect.Call(this.raceRepoMock.Add(expectedRace))
                .IgnoreArguments()
                .Do(new Func<Race, Race>(r =>
                {

                    r.StartDate.Should().Be(expectedRace.StartDate, "wrong start date mapping");
                    r.State.Should().NotBeNull("expected a state instance");
                    r.State.Value.Should().Be(RaceStateEnum.Opened, "wrong race state mapping");
                    r.Category.Should().NotBeNull("expected a category instance");
                    r.Category.Value.Should().Be(expectedRace.Category.Value, "wrong category mapping");
                    r.EndDate.Should().Be(expectedRace.EndDate, "wrong end date mapping");
                    r.Id.Should().Be(Guid.Empty, "wrong id value");
                    r.MechanicsMaxAmount.Should().Be(expectedRace.MechanicsMaxAmount, "wrong mechanics mapping");

                    return r;
                }))
                .Repeat.Once();

            Expect.Call(delegate { this.uow.Commit(); })
                .Repeat.Once();

            this.mockRepository.ReplayAll();

            // SUT
            var result = this.controller.Add(model);
            this.mockRepository.VerifyAll();

            // Asserts
            result.Should().NotBeNull("Expected a valid view instance");
        }
    }
}
